import isEmail from 'validator/lib/isEmail';
import { data, getData, setData } from './dataStore';
import { Error, TokenReturn, UserReturn, users, Tokens } from './interface';
import { v4 as uuidv4 } from 'uuid';
import { isValidNameLength, isValidNameContains, isValidPasswordLength, isValidPasswordContains, isValidToken } from './check';

export function adminAuthRegister(
    email: string,
    password: string,
    nameFirst: string,
    nameLast: string
): TokenReturn | Error {
    const data = getData();
    if (data.users.some(user => user.email.toLowerCase() === email.toLowerCase())) {
        return { error: 'Email address is used by another user.' };
    }

    if (!isEmail(email)) {
        return { error: 'Email is invalid.' };
    }

    if (!isValidNameLength(nameFirst)) {
        return { error: 'NameFirst is less than 2 characters or more than 20 characters.' };
    }

    if (!isValidNameContains(nameFirst)) {
        return { error: 'NameFirst contains characters other than lowercase letters, uppercase letters, spaces, hyphens, or apostrophes.' };
    }

    if (!isValidNameLength(nameLast)) {
        return { error: 'NameLast is less than 2 characters or more than 20 characters.' };
    }

    if (!isValidNameContains(nameLast)) {
        return { error: 'NameLast contains characters other than lowercase letters, uppercase letters, spaces, hyphens, or apostrophes.' };
    }

    if (!isValidPasswordLength(password)) {
        return { error: 'Password is less than 8 characters.' };
    }

    if (!isValidPasswordContains(password)) {
        return { error: 'Password does not contain at least one number and at least one letter.' };
    }

    const newUser: users = {
        userID: data.users.length + 1,
        QuizID: [],
        FirstName: nameFirst,
        LastName: nameLast,
        email: email,
        password: password,
        usedPasswords: [],
        numSuccessfulLogins: 0,
        numFailedPasswordsSinceLastLogin: 0,
    };
    data.users.push(newUser);
    
    const newSessionId = uuidv4();
    if (!data.Tokens[newUser.userID]) {
        data.Tokens[newUser.userID] = [];
    }
    data.Tokens[newUser.userID].push(newSessionId);

    setData(data);
    
    return { token: newSessionId };
}

export function adminAuthLogin(email: string, password: string) {
    let targetIndex = data.users.findIndex(user => user.email === email);

    if (targetIndex === -1) {
        return {error: 'Email address does not exist.'};
    }

    const userData = data.users[targetIndex];
    if (userData.password !== password) {
        return {error: 'Password is not correct for the given email.'};
    }

    let uId = userData.userID;

    let tokens = data.Tokens;
    if (!tokens[uId]) {
        tokens[uId] = [];
    }
    const newSessionId = uuidv4();
    tokens[uId].push(newSessionId);

    setData(data);
    return { token: newSessionId };
}

export function adminUserDetails(token: string): UserReturn | Error {
    const data = getData();

    const userId = isValidToken(token);
    if (!userId) {
        return { error: 'Token is empty or invalid (does not refer to valid logged in user session)' };
    }

    const targetUser = data.users.find(user => user.userID === userId);
    if (!targetUser) {
        return { error: 'User not found' };
    }
  
    return { 
        user: {
            userId: targetUser.userID,
            name:  `${targetUser.FirstName} ${targetUser.LastName}`,
            email: targetUser.email,
            numSuccessfulLogins: targetUser.numSuccessfulLogins,
            numFailedPasswordsSinceLastLogin: targetUser.numFailedPasswordsSinceLastLogin
        }
    }
}

export function adminAuthLogout(token: string) {
    let found = false;
    let userId = -1;

    for (const [id, tokens] of Object.entries(data.Tokens)) {
        const tokenIndex = tokens.indexOf(token);
        if (tokenIndex !== -1) {
            tokens.splice(tokenIndex, 1);
            userId = parseInt(id);
            found = true;
            break;
        }
    }

    if (!found) {
        // return { error: 'Token not found or already expired.' };
        return { error: 'error' };
    }

    // Save changes to data
    setData(data);
    return {};
}